//<<<+++OPENSOURCE
//<<<+++OPENSOURCE_LICENSE
/**
 * @addtogroup FPDFAPI
 * @{
 */

/**
 * @file
 * @brief PDF Basic Object Classes
 *
 * PDF supports eight basic types of objects:
 * - Boolean values				CPDF_Boolean
 * - Integer and real numbers	CPDF_Number
 * - Strings					CPDF_String
 * - Names						CPDF_Name
 * - Arrays						CPDF_Array
 * - Dictionaries				CPDF_Dictionary
 * - Streams					CPDF_Stream
 * - The null object			CPDF_Null
 *
 * Addtional type of object:	CPDF_Reference
 * 
 * Objects may be labeled so that they can be referred to by other objects. A labeled 
 * object is called an indirect object.
 */

//<<<+++OPENSOURCE_MUST_BEGIN
#ifndef _FPDF_OBJECTS_
#define _FPDF_OBJECTS_

#ifndef _FXCRT_EXTENSION_
	#include "../fxcrt/fx_ext.h"
#endif
//<<<+++OPENSOURCE_MUST_END

class CPDF_Document;
class CPDF_IndirectObjects;

class CPDF_Null;
class CPDF_Boolean;
class CPDF_Number;
class CPDF_String;
class CPDF_Stream;
class CPDF_StreamAcc;
class CPDF_StreamFilter;
class CPDF_Array;
class CPDF_Dictionary;
class CPDF_Reference;
class IPDF_DocParser;
class IFX_FileRead;
class CPDF_CryptoHandler;
//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
class CPDF_AttachmentAcc;

#ifndef FOXIT_CHROME_BUILD
#if !defined(_FPDFAPI_MINI_) || defined(_FXCORE_FEATURE_ALL_)
/** @brief enable object modification tracking (currently not available in FPDFEMB). */
#define _FPDF_OBJ_MODIFIED_
#endif
#endif
//<<<+++OPENSOURCE_END

/**
 * @name Object types in PDF. Return by CPDF_Object::GetType() function.
 */
/*@{*/

/** @brief invalid object. */
#define PDFOBJ_INVALID		0
/** @brief Boolean object. */
#define	PDFOBJ_BOOLEAN		1
/** @brief Number object. */
#define PDFOBJ_NUMBER		2
/** @brief String object. */
#define PDFOBJ_STRING		3
/** @brief Name object. */
#define PDFOBJ_NAME			4
/** @brief Array object. */
#define PDFOBJ_ARRAY		5
/** @brief Dictionary object. */
#define PDFOBJ_DICTIONARY	6
/** @brief Stream object. */
#define PDFOBJ_STREAM		7
/** @brief Null object. */
#define PDFOBJ_NULL			8
/** @brief Reference object. */
#define PDFOBJ_REFERENCE	9

/*@}*/ 

/** Callback function is used to create file stream I/O to create PDF Stream object. */
typedef IFX_FileStream* (*FPDF_LPFCloneStreamCallback)(CPDF_Stream *pStream, FX_LPVOID pUserData);

/** @brief Base class for all PDF syntax objects */
class CPDF_Object : public CFX_Object
{
public:
	/** Get type of the object. Returns one of the PDFOBJ_xxxx constants */
	int						GetType() const { return m_Type; }

	/** Get indirect number of the object. 0 for direct object */
	FX_DWORD				GetObjNum() const { return m_ObjNum; }

	/**
	 * Compare with another object.
	 *
	 * @param[in] pObj		The input object.
	 * @return Non-zero means identical, otherwise not identical. 
	 */
	FX_BOOL					IsIdentical(CPDF_Object* pObj) const;

	/**
	 * Get a complete clone. The bDirect parameter specifies whether a totally direct copy
	 * is requested (without any reference inside, so the copy can be copied to other document).
	 *
	 * @param[in] bDirect	Whether a totally direct copy is requested.
	 * @return A complete clone object.
	 */
	CPDF_Object*			Clone(FX_BOOL bDirect = FALSE) const;

	/**
	 * Get a clone for direct object, or a reference for indirect object.
	 *
	 * @param[in] pObjs		The indirect object collection.
	 * @return A clone or reference object.
	 */
	CPDF_Object*			CloneRef(CPDF_IndirectObjects* pObjs) const;

	/**
	 * Get direct object (the object data itself) of an object.
	 * For direct object, return itself; for reference object, return the referred object.
	 */
	CPDF_Object*			GetDirect() const;

	/** Release (free, destroy) the object. This function has no effect to indirect objects. */
	void					Release();

	/**
	 * Get string value of the object. Applicable to string, name, and number objects.
	 * If object type not supported, empty string is returned.
	 */
	CFX_ByteString			GetString() const;

	/**
	 * Get string value of the object. Only applicable to string and name.
	 */
	CFX_ByteStringC			GetConstString() const;

	/**
	 * Get Unicode text value of the object. Applicable to string and stream objects.
	 * If object type not supported, empty string is returned.
	 * We assume the original text are encoding in PDF text encoding scheme.
	 * The returned text is encoded in UTF-16LE encoding.
	 * A character mapper can be used to convert the original text (if not already encoded in Unicode).
	 * If no character mapper used, PDFDocEncoding mapping is used.
	 *
	 * @param[in] pCharMap		The input character mapper.
	 * @return An Unicode text value.
	 */
	CFX_WideString			GetUnicodeText(CFX_CharMap* pCharMap = NULL) const;

	/**
	 * Get float number value of the object. Applicable to number objects only.
	 * If object type is not number, 0.0f is returned.
	 * FIX: when FIX format is used, the returned value will be in FIX24.8 format.
	 */
	FX_FLOAT				GetNumber() const;

	/** Get a FIX16.16 number if FIX format is used. When FIX format not used, this function is same as CPDF_Object::GetNumber(). */
	FX_FLOAT				GetNumber16() const;

	/**
	 * Get integer number value of the object. Applicable to number and boolean objects.
	 * If object type not supported, 0 is returned.
	 */
	int						GetInteger() const;

	/**
	 * Get dictionary value of the object. Applicable to dictionaries or stream only.
	 * NULL is returned for other types of objects.
	 */
	CPDF_Dictionary*		GetDict() const;

	/**
	 * Get array value of the object. Applicable to arrays only.
	 * NULL is returned for non-array objects.
	 */
	CPDF_Array*				GetArray() const;
	/**
	 * Set string value into the object. Applicable to boolean, number, string and name objects.
	 * For non-supported object types, this function does nothing.
	 *
	 * @param[in] str			The input string value.
	 */
	void					SetString(const CFX_ByteString& str);

	/**
	 * Set text encoded in Unicode (UTF-16LE format). Applicable to string and stream objects.
	 * "len" is number of characters, not bytes. -1 for null terminated string.
	 *
	 * @param[in] pUnicodes		Pointer to UTF-16LE format characters.
	 * @param[in] len			Number of the input characters.
	 */
	void					SetUnicodeText(FX_LPCWSTR pUnicodes, int len=-1);
	/** Get type of direct object without loading it. */
	int						GetDirectType() const;
    
	/**
	 * Object modification tracking. It's applied to indirect object only. When an indirect
	 * object is loaded from a parser, it's set to "not modified". Then any change to it or
	 * object inside it will set the object to "modified".
	 * When a new object is added to indirect object, it's set to "modified".
	 */
#ifdef _FPDF_OBJ_MODIFIED_
    //<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/** Whether the object has been "modified". */
	FX_BOOL					IsModified() const { return m_bModified; }
	/**
	 * Change the object's "modified" flag.
	 *
	 * @param[in] bModified		The "modified" flag. TRUE means "modified".
	 */
	void					SetModified(FX_BOOL bModified) { m_bModified = bModified; }

	/** Get the container of this object. */
	CPDF_Object*			GetContainer() const { return m_pContainer; }
	/**
	 * Set the container of this object.
	 *
	 * @param[in] pContainer	The container of this object.
	 */
	void					SetContainer(CPDF_Object* pContainer) { m_pContainer = pContainer; }
    //<<<+++OPENSOURCE_END
#else
	FX_BOOL					IsModified() const { return FALSE; }
#endif
    
    //<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/** Parse an object from a memory buffer. NOTE: parsing indirect reference inside the string will
	 * bring undefined result.
	 *
	 * @param[in] str		A string containing the object
	 * @return parsed object, or NULL if error.
	 */
	static CPDF_Object*		ParseString(FX_BSTR str);
    //<<<+++OPENSOURCE_END
protected:
#ifdef _FPDF_OBJ_MODIFIED_
    //<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/** object type. Defined above. */
	FX_BYTE 				m_Type;
	/** modified flags. */
	FX_BYTE					m_bModified;
	/** Container of this object. */
	CPDF_Object*			m_pContainer;
	/** Set "modified" flag. */
	void					SetModified() { if (m_pContainer) m_pContainer->SetModified(); else m_bModified = TRUE; }
	/** Default constructor. The object can't be directly constructed. Construct derived class object instead. */
	CPDF_Object() { m_ObjNum = 0; m_pContainer = NULL; m_Type = PDFOBJ_INVALID;}
    //<<<+++OPENSOURCE_END
#else
	FX_DWORD				m_Type;
	CPDF_Object() { m_ObjNum = 0; }
#endif

	/** object number for indirect object, or 0 for direct object. */
	FX_DWORD 				m_ObjNum;

	/** Destroy the object. */
	void					Destroy();
	
	/** The destructor. The object can't be directly deleted. Use CPDF_Object::Release() instead. */
	~CPDF_Object() {}

	friend class			CPDF_IndirectObjects;
	friend class			CPDF_Parser;
	friend class			CPDF_SyntaxParser;

private:
	CPDF_Object(const CPDF_Object& src) {}		// disable copy constructors for all objects. Use Clone() please
	CPDF_Object* CloneInternal(FX_BOOL bDirect, CFX_MapPtrToPtr* visited) const;
};

/** @brief PDF Boolean object class. */
class CPDF_Boolean : public CPDF_Object
{
public:
	/**
	 * Create a CPDF_Boolean object from a single boolean value.
	 *
	 * @param[in] value		A boolean value.
	 * @return A CPDF_Boolean object.
	 */
	static CPDF_Boolean*	Create(FX_BOOL value) { return FX_NEW CPDF_Boolean(value); }

	/** Construct an uninitialized boolean object. */
	CPDF_Boolean()  { m_Type = PDFOBJ_BOOLEAN; }
	/**
	 * Construct a boolean object with a boolean value.
	 * 
	 * @param[in] value		The input boolean value.
	 */
	CPDF_Boolean(FX_BOOL value)  { m_Type = PDFOBJ_BOOLEAN; m_bValue = value; }

	/**
	 * Compare with another boolean object.
	 *
	 * @param[in] pOther	The other boolean object.
	 * @return Non-zero means identical, otherwise not identical.
	 */
	FX_BOOL					Identical(CPDF_Boolean* pOther) const { return m_bValue == pOther->m_bValue; }

protected:
	/** The boolean value. */
	FX_BOOL					m_bValue;

	friend class			CPDF_Object;
};

/** @brief PDF Number object class. */
class CPDF_Number : public CPDF_Object
{
public:
	/**
	 * Create a CPDF_Number object from an integer.
	 *
	 * @param[in] value		The input integer.
	 * @return A CPDF_Number object.
	 */
	static CPDF_Number*		Create(int value) { return FX_NEW CPDF_Number(value); }
	/**
	 * Create a CPDF_Number object from a floating-point value.
	 *
	 * @param[in] value		The input floating-point.
	 * @return A CPDF_Number object.
	 */
	static CPDF_Number*		Create(FX_FLOAT value) { return FX_NEW CPDF_Number(value); }
	/**
	 * Create a CPDF_Number object from a non-buffered byte string.
	 *
	 * @param[in] str		The input non-buffered byte string.
	 * @return A CPDF_Number object.
	 */
	static CPDF_Number*		Create(FX_BSTR str) { return FX_NEW CPDF_Number(str); }
	/**
	 * Create a CPDF_Number object from data.
	 *
	 * @param[in] bInteger	Whether the input data is actually an integer.
	 * @param[in] pData		The input data.
	 * @return A CPDF_Number object.
	 */
	static CPDF_Number*		Create(FX_BOOL bInteger, void* pData) { return FX_NEW CPDF_Number(bInteger, pData); }

	/** Construct an Empty CPDF_Number object. */
	CPDF_Number()  { m_Type = PDFOBJ_NUMBER; }
	/** Construct from data. */
	CPDF_Number(FX_BOOL bInteger, void* pData);
	/**
	 * Construct from an integer.
	 *
	 * @param[in] value		The input integer.
	 */
	CPDF_Number(int value);
	/**
	 * Construct from a floating-point.
	 *
	 * @param[in] value		The input floating-point.
	 */
	CPDF_Number(FX_FLOAT value);
	/**
	 * Construct from a non-buffered byte string.
	 *
	 * @param[in] str		The input non-buffered byte string.
	 */
	CPDF_Number(FX_BSTR str);

	/**
	 * Compare with another CPDF_Number object.
	 *
	 * @param[in] pOther	The other CPDF_Number object.
	 * @return Non-zero means identical, otherwise not identical.
	 */
	FX_BOOL					Identical(CPDF_Number* pOther) const;

	/** Get a byte string from this object. */
	CFX_ByteString			GetString() const;
    
	/**
	 * Set a non-buffered byte string.
	 *
	 * @param[in] str		The input non-buffered byte string.
	 */
	void					SetString(FX_BSTR str);
    
	/** Whether the number is an integer. */
	FX_BOOL					IsInteger() const { return m_bInteger; }

	/** Get the integer value. */
	int						GetInteger() const { return m_bInteger ? m_Integer : (int)m_Float; }
	/** Get the FIX24.8 value. */
	FX_FLOAT				GetNumber() const { return m_bInteger ? (FX_FLOAT)m_Integer : m_Float; }
	/**
	 * Set a FIX24.8 value.
	 *
	 * @param[in] value		The input FIX24.8 value.
	 */
	void					SetNumber(FX_FLOAT value);
	/** Get the FIX16.16 value. */
	FX_FLOAT			GetNumber16() const { return GetNumber(); }
    //<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
	 * Set a FIX16.16 value.
	 *
	 * @param[in] value		The input FIX16.16 value.
	 */
	void					SetNumber16(FX_FLOAT value) { SetNumber(value); }
    //<<<+++OPENSOURCE_END
	/** Get the floating-point value. */
	FX_FLOAT				GetFloat() const { return m_bInteger ? (FX_FLOAT)m_Integer : m_Float; }

protected:
	/** Whether it's an integer. */
	FX_BOOL					m_bInteger;
	/** Number data union. */
	union {
		/** Integer value. */
		int					m_Integer;
		/** Floating-point value. */
		FX_FLOAT			m_Float;
	};

	friend class			CPDF_Object;
};

/** @brief PDF String object class. */
class CPDF_String : public CPDF_Object
{
public:
	/**
	 * Create a CPDF_String from a byte string.
	 *
	 * @param[in] str		The input byte string.
	 * @return A CPDF_String object.
	 */
	static CPDF_String*		Create(const CFX_ByteString& str, FX_BOOL bHex = FALSE) { return FX_NEW CPDF_String(str, bHex); }
	/**
	 * Create a CPDF_String from a wide string.
	 *
	 * @param[in] str		The input wide string.
	 * @return A CPDF_String object. 
	 */
	static CPDF_String*		Create(const CFX_WideString& str) { return FX_NEW CPDF_String(str); }

	/** Construct an empty CPDF_String object. */
	CPDF_String() { m_Type = PDFOBJ_STRING; m_bHex = FALSE; }
	/**
	 * Construct from a byte string. Optionally hex flag can be set.
	 *
	 * @param[in] str		The input byte string.
	 * @param[in] bHex		The input hex flag.
	 */
	CPDF_String(const CFX_ByteString& str, FX_BOOL bHex = FALSE) : m_String(str) { m_Type = PDFOBJ_STRING; m_bHex = bHex;  }
	/**
	 * Construct from a wide string.
	 *
	 * @param[in] str		The input wide string.
	 */
	CPDF_String(const CFX_WideString& str);

	/** Get a ref to the CPDF_String data. */
	CFX_ByteString&			GetString() { return m_String; }

	/**
	 * Compare with another CPDF_String object.
	 *
	 * @param[in] pOther	The other CPDF_String object.
	 * @return Non-zero means identical, otherwise not identical.
	 */
	FX_BOOL					Identical(CPDF_String* pOther) const { return m_String == pOther->m_String; }

    //<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
	 * Change the hex flag.
	 *
	 * @param[in] bHex		The input hex flag.
	 */
	void					SetHex(FX_BOOL bHex) { m_bHex = bHex; }
    //<<<+++OPENSOURCE_END
	/** Whether this CPDF_String object has the hex flag. */
	FX_BOOL					IsHex() const { return m_bHex; }

protected:
	/** The string. */
	CFX_ByteString			m_String;
	/** The hex flag. */
	FX_BOOL					m_bHex;

	friend class			CPDF_Object;
};

/** @brief PDF Name object class. */
class CPDF_Name : public CPDF_Object
{
public:
	/**
	 * Create a CPDF_Name object from a byte string.
	 *
	 * @param[in] str		The input byte string.
	 * @return A CPDF_Name object.
	 */ 
	static CPDF_Name*		Create(const CFX_ByteString& str) { return FX_NEW CPDF_Name(str); }
	/**
	 * Create a CPDF_Name object from a non-buffered byte string.
	 *
	 * @param[in] str		The input non-buffered byte string.
	 * @return A CPDF_Name object.
	 */
	static CPDF_Name*		Create(FX_BSTR str) { return FX_NEW CPDF_Name(str); }
	/**
	 * Create a CPDF_Name object from an zero-terminated ANSI C string.
	 *
	 * @param[in] str		The input zero-terminated ANSI C string.
	 * @return A CPDF_Name object.
	 */
	static CPDF_Name*		Create(FX_LPCSTR str) { return FX_NEW CPDF_Name(str); }

	/**
	 * Construct from a byte string.
	 *
	 * @param[in] str		The input byte string.
	 */
	CPDF_Name(const CFX_ByteString& str) : m_Name(str) { m_Type = PDFOBJ_NAME; }
	/**
	 * Construct from a non-buffered byte string.
	 *
	 * @param[in] str		The input non-buffered byte string.
	 */
	CPDF_Name(FX_BSTR str) : m_Name(str) { m_Type = PDFOBJ_NAME; }
	/**
	 * Construct from a zero-terminated ANSI C string.
	 *
	 * @param[in] str		The input zero-terminated ANSI C string.
	 */
	CPDF_Name(FX_LPCSTR str) : m_Name(str) { m_Type = PDFOBJ_NAME; }

	/** Get a ref to CPDF_Name data. */
	CFX_ByteString&			GetString() { return m_Name; }

	/**
	 * Compare with another CPDF_Name object.
	 *
	 * @param[in] pOther	The other CPDF_Name object.
	 * @return Non-zero means identical, otherwise not identical.
	 */
	FX_BOOL					Identical(CPDF_Name* pOther) const { return m_Name == pOther->m_Name; }

protected:
	/** The name. Without the preceding "/". */
	CFX_ByteString			m_Name;

	friend class			CPDF_Object;
};

/** @brief PDF Array object class. */
class CPDF_Array : public CPDF_Object
{
public:
	/** Create an empty array. */
	static CPDF_Array*		Create() { return FX_NEW CPDF_Array(); }

	/** Construct an empty array. */
	CPDF_Array()  { m_Type = PDFOBJ_ARRAY; }

	/** Get the count of objects in the array. */
	FX_DWORD				GetCount() const { return m_Objects.GetSize(); }

	/**
	 * Get reference to element. Returns direct reference to the element.
	 * Don't call Release() for the returned object.
	 *
	 * @param[in] index		Specifies the zero-based index in the array.
	 * @return Pointer to specified element.
	 */
	CPDF_Object*			GetElement(FX_DWORD index) const;
	/**
	 * Returns direct or referred indirect object. Don't call Release() for the returned object.
	 *
	 * @param[in] index		Specifies the zero-based index in the array.
	 * @return A direct or referred indirect object.
	 */
	CPDF_Object*			GetElementValue(FX_DWORD index) const;

	/**
	 * @name Get PDF common data types from an array.
	 */
	/*@{*/

	/** Get a matrix from the array. */
	CFX_AffineMatrix		GetMatrix();
	/** Get a rectangle from the array. */
	CFX_FloatRect			GetRect();

	/*@}*/ 

	/**
	 * @name Get data from element.
	 */
	/*@{*/

	/**
	 * Get a string with specified position.
	 *
	 * @param[in] index		Specifies the zero-based index in the array.
	 * @return A byte string.
	 */
	CFX_ByteString			GetString(FX_DWORD index) const;
	/**
	 * Get a const string with specified position. Only applicable to string and name.
	 *
	 * @param[in] index		Specifies the zero-based index in the array.
	 * @return A byte string.
	 */
	CFX_ByteStringC			GetConstString(FX_DWORD index) const;
	/**
	 * Get an integer with specified position.
	 *
	 * @param[in] index		Specifies the zero-based index in the array.
	 * @return An integer.
	 */
	int						GetInteger(FX_DWORD index) const;
	/**
	 * Get a number with specified position.
	 *
	 * @param[in] index		Specifies the zero-based index in the array.
	 * @return A FIX24.8 number.
	 */
	FX_FLOAT				GetNumber(FX_DWORD index) const;
	/**
	 * Get a dictionary object with specified position.
	 *
	 * @param[in] index		Specifies the zero-based index in the array.
	 * @return A dictionary object.
	 */
	CPDF_Dictionary*		GetDict(FX_DWORD index) const;
	/**
	 * Get a stream object with specified position.
	 *
	 * @param[in] index		Specifies the zero-based index in the array.
	 * @return a stream object.
	 */
	CPDF_Stream*			GetStream(FX_DWORD index) const;
	/**
	 * Get an array object with specified position.
	 *
	 * @param[in] index		Specifies the zero-based index in the array.
	 * @return An array object.
	 */
	CPDF_Array*				GetArray(FX_DWORD index) const;

	/**
	 * Get a floating-point with specified position.
	 *
	 * @param[in] index		Specifies the zero-based index in the array.
	 * @return A floating-point value.
	 */
	FX_FLOAT				GetFloat(FX_DWORD index) const { return GetNumber(index); }

	/*@}*/ 

    
	/**
	 * @name Modify elements.
	 */
	/*@{*/

	/**
	 * Change the element at specified position.
	 *
	 * @param[in] index		Specifies the zero-based index in the array.
	 * @param[in] pObj		The input object. Caller must NOT free it.
	 * @param[in] pObjs		The indirect object collection, required if pObj is an indirect object. In this case,
	 *						a reference object will be created and inserted into the array.
	 */
	void					SetAt(FX_DWORD index, CPDF_Object* pObj, CPDF_IndirectObjects* pObjs = NULL);
	
	/**
	 * Insert an element at specified position.
	 *
	 * @param[in] index		Specifies the zero-based index in the array.
	 * @param[in] pObj		The input object. Caller must NOT free it.
	 * @param[in] pObjs		The indirect object collection, required if pObj is an indirect object. In this case,
	 *						a reference object will be created and inserted into the array.
	 */
	void					InsertAt(FX_DWORD index, CPDF_Object* pObj, CPDF_IndirectObjects* pObjs = NULL);
	/**
	 * Remove an element.
	 *
	 * @param[in] index		Specifies the zero-based index in the array.
	 */
	void					RemoveAt(FX_DWORD index);

	/*@}*/ 
    
	/**
	 * Adding element. Please note all elements will be managed with the array object, so the object pointer
	 * must NOT be freed by caller.
	 *
	 * @param[in] pObj		The input object. Caller can't free it.
	 * @param[in] pObjs		The indirect object collection, required if pObj is an indirect object. In this case,
	 *						a reference object will be created and inserted into the array.
	 */
	void					Add(CPDF_Object* pObj, CPDF_IndirectObjects* pObjs = NULL);

	/**
	 * @name Adding different type of elements. Please use the following functions instead of the above generic
	 * CPDF_Array::Add() function, whenever possible.
	 */
	/*@{*/
	/**
	 * Add a number object with a FIX24.8 value.
	 *
	 * @param[in] f			The input FIX24.8 value.
	 */
	void					AddNumber(FX_FLOAT f);
	/**
	 * Add a number object with an integer value.
	 *
	 * @param[in] i			The input integer value.
	 */
	void					AddInteger(int i);
	/**
	 * Add a string object.
	 *
	 * @param[in] str		The input string data.
	 */
	void					AddString(const CFX_ByteString& str);
	/**
	 * Add a name object.
	 *
	 * @param[in] str		The input name data.
	 */
	void					AddName(const CFX_ByteString& str);
	/**
	 * Add a reference object with object number.
	 *
	 * @param[in] pDoc		The input indirect object collection.
	 * @param[in] objnum	The referred object number.
	 */
	void					AddReference(CPDF_IndirectObjects* pDoc, FX_DWORD objnum);
	/**
	 * Add a reference object with object pointer.
	 *
	 * @param[in] pDoc		The input indirect object collection.
	 * @param[in] obj		The input object.
	 */
	void					AddReference(CPDF_IndirectObjects* pDoc, CPDF_Object* obj) { AddReference(pDoc, obj->GetObjNum()); }
	/*@}*/ 

	/**
	 * Get a FIX16.16 value at specified position.
	 *
	 * @param[in] index		Specifies the zero-based index in the array.
	 * @return A FIX16.16 value.
	 */
	FX_FLOAT			GetNumber16(FX_DWORD index) const { return GetNumber(index); }
	/**
	 * Add a FIX16.16 number.
	 *
	 * @param[in] value		The input FIX16.16 value.
	 */
	void					AddNumber16(FX_FLOAT value) { AddNumber(value); }
    
	/**
	 * Compare with another object.
	 *
	 * @param[in] pOther		The other CPDF_Array object.
	 * @return Non-zero means identical, otherwise not identical.
	 */
	FX_BOOL					Identical(CPDF_Array* pOther) const;

protected:
	/** The destructor. The object can't be deleted directly, use CPDF_Object::Release() instead. */
	~CPDF_Array();

	/** Pointers to CPDF_Object. */
	CFX_PtrArray			m_Objects;

	friend class			CPDF_Object;
};

/** @brief PDF Dictionary object class. */
class CPDF_Dictionary : public CPDF_Object
{
public:
	/** Create an empty dictionary. */
	static CPDF_Dictionary*	Create() { return FX_NEW CPDF_Dictionary(); }

	/** Construct an empty dictionary. */
	CPDF_Dictionary()  { m_Type = PDFOBJ_DICTIONARY; }

	/**
	 * @name Getting element pointers
	 */
	/*@{*/

	/**
	 * Get direct reference to the object (include reference), Don't call CPDF_Object::Release() for the returned object.
	 *
	 * @param[in] key		The input key string.
	 * @return A pointer to the object (include reference).
	 */
	CPDF_Object*			GetElement(FX_BSTR key) const;
	/**
	 * Returns direct or referred indirect object, Don't call CPDF_Object::Release() for the returned object.
	 *
	 * @param[in] key		The input key string.
	 * @return A pointer to direct or referred indirect object.
	 */
	CPDF_Object*			GetElementValue(FX_BSTR key) const;
	
	/*@}*/ 

	/**
	 * @name Getting element data
	 */
	/*@{*/

	/**
	 * Get the string data for the element specified by key.
	 *
	 * @param[in] key		The input key string.
	 * @return A byte string for the specified element.
	 */
	CFX_ByteString			GetString(FX_BSTR key) const;
	/**
	 * Get the const string data for the element specified by key. Only applicable to string and name.
	 *
	 * @param[in] key		The input key string.
	 * @return A byte string for the specified element.
	 */
	CFX_ByteStringC			GetConstString(FX_BSTR key) const;
	/**
	 * Get the string data for the element specified by key with a default string additionally.
	 *
	 * @param[in] key			The input key string.
	 * @param[in] default_str	The default string.
	 * @return A byte string for the specified element.
	 */
	CFX_ByteString			GetString(FX_BSTR key, FX_BSTR default_str) const;
	/**
	 * Get the string data for the element specified by key with a default string additionally. Only applicable to string and name.
	 *
	 * @param[in] key			The input key string.
	 * @param[in] default_str	The default string.
	 * @return A byte string for the specified element.
	 */
	CFX_ByteStringC			GetConstString(FX_BSTR key, FX_BSTR default_str) const;
	/**
	 * Get the Unicode string data for the element specified by key with a character mapping.
	 *
	 * @param[in] key			The input key string.
	 * @param[in] pCharMap		The input character mapping.
	 * @return An Unicode string for the specified element.
	 */
	CFX_WideString			GetUnicodeText(FX_BSTR key, CFX_CharMap* pCharMap = NULL) const;
	/**
	 * Get the integer data for the element specified by key.
	 *
	 * @param[in] key			The input key string.
	 * @return An integer value for the specified element.
	 */
	int						GetInteger(FX_BSTR key) const;
	/**
	 * Get the integer data for the element specified by key with a default integer value.
	 *
	 * @param[in] key			The input key string.
	 * @param[in] default_int	The default integer value.
	 * @return An integer value for the specified element.
	 */
	int						GetInteger(FX_BSTR key, int default_int) const;
	/**
	 * Get the boolean data for the element specified by key with a default boolean value.
	 *
	 * @param[in] key			The input key string.
	 * @param[in] bDefault		The default boolean value.
	 * @return A boolean value for the specified element.
	 */
	FX_BOOL					GetBoolean(FX_BSTR key, FX_BOOL bDefault = FALSE) const;
	/**
	 * Get the number data for the element specified by key.
	 *
	 * @param[in] key			The input key string.
	 * @return A FIX24.8 value for the specified element.
	 */
	FX_FLOAT				GetNumber(FX_BSTR key) const;
	/**
	 * Get a dictionary object specified by key.
	 *
	 * @param[in] key			The input key string.
	 * @return A dictionary object.
	 */
	CPDF_Dictionary*		GetDict(FX_BSTR key) const;
	/**
	 * Get a stream object specified by key.
	 *
	 * @param[in] key			The input key string.
	 * @return A stream object.
	 */
	CPDF_Stream*			GetStream(FX_BSTR key) const;
	/**
	 * Get an array object specified by key.
	 *
	 * @param[in] key			The input key string.
	 * @return An array object.
	 */
	CPDF_Array*				GetArray(FX_BSTR key) const;
	/**
	 * Get a rectangle for the element specified by key.
	 *
	 * @param[in] key			The input key string.
	 * @return A rectangle.
	 */
	CFX_FloatRect			GetRect(FX_BSTR key) const;
	/**
	 * Get a matrix for the element specified by key.
	 *
	 * @param[in] key			The input key string.
	 * @return A matrix.
	 */
	CFX_AffineMatrix		GetMatrix(FX_BSTR key) const;

	/**
	 * Get a floating-point value for the element specified by key.
	 *
	 * @param[in] key			The input key string.
	 * @return A floating-point value.
	 */
	FX_FLOAT				GetFloat(FX_BSTR key) const { return GetNumber(key); }

	/*@}*/ 

	/**
	 * Whether the element specified by key exist.
	 *
	 * @param[in] key			The input key string.
	 * @return Non-zero means exist, otherwise not.
	 */
	FX_BOOL					KeyExist(FX_BSTR key) const;

	/** Get the position for the first element. */
	FX_POSITION				GetStartPos() const;
	/**
	 * Returns direct reference to the element and move the position to next. Don't call Release() for the returned object.
	 *
	 * @param[in,out] pos		Input current position and receive the next position.
	 * @param[out] key			It receives the current key string.
	 * @return	The direct reference to the current element.
	 */
	CPDF_Object*			GetNextElement(FX_POSITION& pos, CFX_ByteString& key) const;

	/**
	 * Setting element data. Please note all elements will be managed with the dictionary object, so the object pointer
	 * must NOT be freed by caller.
	 *
	 * @param[in] key			The input key string.
	 * @param[in] pObj			The input element data.
	 * @param[in] pObjs			The indirect object collection, required if pObj is an indirect object. In this case,
	 *							a reference object will be created and inserted into the dictionary.
	 */
	void					SetAt(FX_BSTR key, CPDF_Object* pObj, CPDF_IndirectObjects* pObjs = NULL);
    
	/**
	 * @name Setting element of different types. Please use the following functions instead of the above generic
	 * CPDF_Dictionary::SetAt() function, whenever possible.
	 */
	/*@{*/

	/**
	 * Set a string of name object for the element specified by key.
	 *
	 * @param[in] key			The input key string.
	 * @param[in] name			The name string.
	 */
	void					SetAtName(FX_BSTR key, const CFX_ByteString& name);
	
	/**
	 * Set a string of string object for the element specified by key.
	 *
	 * @param[in] key			The input key string.
	 * @param[in] string		The input string.
	 */
	void					SetAtString(FX_BSTR key, const CFX_ByteString& string);
	
	/**
	 * Set an integer of number object for the element specified by key.
	 *
	 * @param[in] key			The input key string.
	 * @param[in] i				The input integer.
	 */
	void					SetAtInteger(FX_BSTR key, int i);
	
	/**
	 * Set a FIX24.8 of number object for the element specified by key.
	 *
	 * @param[in] key			The input key string.
	 * @param[in] f				The input FIX24.8 value.
	 */
	void					SetAtNumber(FX_BSTR key, FX_FLOAT f);
	/**
	 * Set a reference object for the element specified by key.
	 *
	 * @param[in] key			The input key string.
	 * @param[in] pDoc			The indirect objects collection for the reference object.
	 * @param[in] objnum		The referred object number for the reference object.
	 */
	void					SetAtReference(FX_BSTR key, CPDF_IndirectObjects* pDoc, FX_DWORD objnum);
	/**
	 * Set a reference object for the element specified by key.
	 *
	 * @param[in] key			The input key string.
	 * @param[in] pDoc			The indirect objects collection for the reference object.
	 * @param[in] obj			The referred object pointer for the reference object.
	 */
	void					SetAtReference(FX_BSTR key, CPDF_IndirectObjects* pDoc, CPDF_Object* obj) {SetAtReference(key, pDoc, obj->GetObjNum());}
	/** 
	 * Add a reference object for the element specified by key.
	 * 
	 * @param[in] key			The input key string.
	 * @param[in] pDoc			The indirect objects collection for the reference object.
	 * @param[in] objnum		The referred object number for the reference object.
	*/
	void					AddReference(FX_BSTR key, CPDF_IndirectObjects* pDoc, FX_DWORD objnum);
	/**
	 * Add a reference object for the element specified by key.
	 *
	 * @param[in] key			The input key string.
	 * @param[in] pDoc			The indirect objects collection for the reference object.
	 * @param[in] obj			The referred object pointer for the reference object.
	 */
	void					AddReference(FX_BSTR key, CPDF_IndirectObjects* pDoc, CPDF_Object* obj) {AddReference(key, pDoc, obj->GetObjNum());}
	/**
	 * Set a rectangle for the element specified by key.
	 * 
	 * @param[in] key			The input key string.
	 * @param[in] rect			The input rectangle.
	 */
	void					SetAtRect(FX_BSTR key, const CFX_FloatRect& rect);
	/**
	 * Set a matrix for the element specified by key.
	 * 
	 * @param[in] key			The input key string.
	 * @param[in] matrix		The input matrix.
	 */
	void					SetAtMatrix(FX_BSTR key, const CFX_AffineMatrix& matrix);
	/**
	 * Set a boolean value of boolean object for the element specified by key.
	 * 
	 * @param[in] key			The input key string.
	 * @param[in] bValue		The input boolean value.
	 */
	void					SetAtBoolean(FX_BSTR key, FX_BOOL bValue);

	/*@}*/ 
	
	/**
	 * Remove the element specified by key.
	 *
	 * @param[in] key			The input key string.
	 */
	void					RemoveAt(FX_BSTR key);
	
	/**
	 * Replace the key of the element specified by key with new key string.
	 *
	 * @param[in] oldkey		The old key string.
	 * @param[in] newkey		The new key string.
	 */
	void					ReplaceKey(FX_BSTR oldkey, FX_BSTR newkey);
    
	/**
	 * Compare value with another object.
	 *
	 * @param[in] pDict			The another dictionary.
	 * @return Non-zero means identical, otherwise not identical.
	 */
	FX_BOOL					Identical(CPDF_Dictionary* pDict) const;

	/** Return the number of elements in the dictionary. */
	int						GetCount() const { return m_Map.GetCount(); }

	/** Add a key-value pair to the dictionary, assuming there is no duplicated key existing.
	*	This is a function for quickly building up the whole dictionary, but should be used
	*	with care. If duplicate key happens, only the first value will prevail.
	*/
	void					AddValue(FX_BSTR key, CPDF_Object* pObj);

	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/** Replace all dictionary data with those within another dictionary. Clear the given dictionary.
	 *
	 * @param[in] pDict			The another dictionary.
	 */
	void					MoveData(CPDF_Dictionary* pSrcDict);
	//<<<+++OPENSOURCE_END

protected:
	/** The destructor. The object can't be deleted directly, use CPDF_Object::Release() instead. */
	~CPDF_Dictionary();

	/** Mapping names to pointers of CPDF_Object. using a Compact mapping. */
	CFX_CMapByteStringToPtr	m_Map;
	
	friend class			CPDF_Object;
};

/** @brief PDF Stream object class. */
class CPDF_Stream : public CPDF_Object
{
public:
	/**
	 * Create a stream object from a memory buffer, with a dictionary.
	 *
	 * @param[in] pData			Pointer to the memory buffer.
	 * @param[in] size			The size in bytes of the memory buffer.
	 * @param[in] pDict			The input dictionary for the stream object.
	 * @return A stream object.
	 * 
	 * @see CPDF_Stream::CPDF_Stream().
	 */
	static CPDF_Stream*		Create(FX_LPBYTE pData, FX_DWORD size, CPDF_Dictionary* pDict) 
	{ return FX_NEW CPDF_Stream(pData, size, pDict); }

	/**
	 * Construct a memory based stream. NOTE: the buffer specified by pData parameter will be taken by the stream,
	 * so the caller can not release it. The stream destructor will release it.
	 * The source buffer can be NULL, in this case no data is allocated.
	 * The dictionary is taken by the stream too.
	 *
	 * @param[in] pData			Pointer to the memory buffer.
	 * @param[in] size			The size in bytes of the memory buffer.
	 * @param[in] pDict			The input dictionary for the stream object.
	 */
	CPDF_Stream(FX_LPBYTE pData, FX_DWORD size, CPDF_Dictionary* pDict);

    //<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
	 * Construct a file based stream. May be encrypted. The dictionary is taken by the stream.
	 *
	 * @param[in] pFile			The file access interface.
	 * @param[in] pCrypto		The encrypt-handler of the stream data in the file.
	 * @param[in] offset		The offset in the file.
	 * @param[in] size			The size in bytes of the stream data.
	 * @param[in] pDict			The input dictionary for the stream object.
	 * @param[in] gennum		The generation number for the stream object.
	 */
	CPDF_Stream(IFX_FileRead* pFile, class CPDF_CryptoHandler* pCrypto,
						FX_FILESIZE offset, FX_DWORD size, CPDF_Dictionary* pDict, FX_DWORD gennum);
    //<<<+++OPENSOURCE_END

	/** Get the dictionary of the stream object. */
	CPDF_Dictionary*		GetDict() const { return m_pDict; }

	/**
	 * Set stream data. If pData is NULL, just allocate stream buffer.
	 * The data can be uncompressed or compressed. If it's uncompressed, then previous filter
	 * info will be dropped (if any). If it's compressed, the caller should also maintain
	 * the filter information in the dictionary.
	 * If bKeepBuf is TRUE, the buffer will be maintained and released by the stream object.
	 *
	 * @param[in] pData			The stream data to set.
	 * @param[in] size			The size in bytes of the stream data.
	 * @param[in] bCompressed	Whether the data is compressed.
	 * @param[in] bKeepBuf		Whether the buffer will be maintained by the stream object.
	 */
	void					SetData(FX_LPCBYTE pData, FX_DWORD size, FX_BOOL bCompressed, FX_BOOL bKeepBuf);
    
    //<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/** 
	 * Set stream file.
	 */
	void					SetStreamFile(IFX_FileRead* pFile, FX_FILESIZE offset, FX_DWORD size, FX_BOOL bCompressed);
    //<<<+++OPENSOURCE_END
    
	/**
	 * Initialize a stream with data and dictionary.
	 * If no dictionary specified, the old dictionary is retained.
	 *
	 * @param[in] pData			The stream data to initialize with.
	 * @param[in] size			the size in bytes of the stream data.
	 * @param[in] pDict			The input dictionary for the stream object.
	 */
	void					InitStream(FX_BYTE* pData, FX_DWORD size, CPDF_Dictionary* pDict);

	/**
	 * Initialize a stream with IFX_FileRead object.
	 * If no dictionary specified, the old dictionary is retained.
	 *
	 * @param[in] pFile			The stream data to initialize with.
	 * @param[in] pDict			The input dictionary for the stream object.
	 */
	void					InitStream(IFX_FileRead *pFile, CPDF_Dictionary* pDict);

	/**
	 * Compare value with another object.
	 *
	 * @param[in] pOther		The another stream object.		
	 * @return Non-zero means identical, otherwise not identical.
	 */
	FX_BOOL					Identical(CPDF_Stream* pOther) const;

	/**
	 * Create a stream-based data filter from the PDF stream.
	 * The filter can output either raw data (decrypted) or decoded data.
	 * JBIG2 and JPEG2000 decoding not supported.
	 * Caller must destroy the created filter.
	 *
	 * @param[in] bRaw			Whether the stream filter will do decoding.
	 * @return A stream filter object.
	 */
	CPDF_StreamFilter*		GetStreamFilter(FX_BOOL bRaw = FALSE) const;

	/**
	 * @name Read raw data. NOTE: raw data might have been encrypted.
	 */
	/*@{*/

	/** Get the raw data size in bytes. */
	FX_DWORD				GetRawSize() const { return m_dwSize; }
	/**
	 * Read raw data. 
	 *
	 * @param[in] start_pos		The start position in the stream data to read from.
	 * @param[out] pBuf			The buffer to receive the read data.								
	 * @param[in] buf_size		The size in bytes expected to read.
	 * @return Non-zero means successful, otherwise failed.
	 */
	FX_BOOL					ReadRawData(FX_FILESIZE start_pos, FX_LPBYTE pBuf, FX_DWORD buf_size) const;

	/*@}*/ 

	/** Whether the stream data is memory-based. */
	FX_BOOL					IsMemoryBased() const { return m_GenNum == (FX_DWORD)-1; }

    //<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
	 * Reset the stream data. Use internally when document reparsing is used.
	 *
	 * @param[in] pFile		The new file access interface.
	 * @param[in] pCrypto	The new encrypt handler.
	 * @param[in] offset	The new offset of stream data in the new file.
	 */
	void					ResetFileStream(IFX_FileRead* pFile, class CPDF_CryptoHandler* pCrypto,
									FX_FILESIZE offset, CPDF_Dictionary* pDict);
    //<<<+++OPENSOURCE_END
    
	/**
	 * Get a complete clone.
	 *
	 * @param[in] bDirect		Whether a totally direct copy is requested, affect indirect object.
	 * @param[in] lpfCallback	Callback function is used to create file stream object for CPDF_Stream.
	 * @param[in] pUserData		User private data pointer passed to callback function.
	 * @return A complete clone object.
	 */
	CPDF_Stream*			Clone(FX_BOOL bDirect, FPDF_LPFCloneStreamCallback lpfCallback, FX_LPVOID pUserData) const;

protected:
	/** The destructor. The object can't be deleted directly, use CPDF_Object::Release() instead. */
	~CPDF_Stream();

	/** The dictionary of the stream object. */
	CPDF_Dictionary*		m_pDict;
	/** The size in bytes of the stream data. */
	FX_DWORD				m_dwSize;
	/** The generation number of the object. -1 for memory based stream. */
	FX_DWORD				m_GenNum;
	/** Stream data. */
	union {
		/** For memory based stream. */
		FX_LPBYTE			m_pDataBuf;
		/** For file based stream. */
		IFX_FileRead*		m_pFile;	
	};
	/** The offset in the file. */
	FX_FILESIZE				m_FileOffset;
	/** The encrypt handler for the stream data in the file. */ 
	CPDF_CryptoHandler*		m_pCryptoHandler;

	/** Initialize stream. */
	void					InitStream(CPDF_Dictionary* pDict);

	friend class			CPDF_Object;
	friend class			CPDF_StreamAcc;
	friend class			CPDF_AttachmentAcc;
};

/**
 * @brief Accessor of CPDF_Stream: 
 * This class depends on a stream, it maintains a buffer for the data of a stream.
 * This buffer may be temporary, if the stream is encoded by one or more data encoders.
 * This class doesn't decode any image encoders.
 */
class CPDF_StreamAcc : public CFX_Object
{
public:
	/** The constructor. */
	CPDF_StreamAcc();
	/** The destructor. */
	~CPDF_StreamAcc();

	/**
	 * Must call this function to actually attach to a stream.
	 *
	 * @param[in] pStream			The stream object to be attached to.
	 * @param[in] bRawAccess		Whether access the stream data rawly.
	 * @param[in] estimated_size	The estimated size in bytes of the loaded stream data.
	 * @param[in] bImageAcc			Whether access the image filter or not.
	 */
	void					LoadAllData(const CPDF_Stream* pStream, FX_BOOL bRawAccess = FALSE, 
									FX_DWORD estimated_size = 0, FX_BOOL bImageAcc = FALSE);

	/** Get the stream object attached to. */
	const CPDF_Stream*		GetStream() const { return m_pStream; }
	/** Get the dictionary of the stream object attached to. */
#ifndef _FXM_OPENSOURCE_
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	CPDF_Dictionary*		GetDict() const { return m_pStream->GetDict(); }
	//<<<+++OPENSOURCE_END
#else
	//<<<+++OPENSOURCE_BEGIN LIC==GOOGLE
	CPDF_Dictionary*		GetDict() const { return m_pStream ? m_pStream->GetDict() : NULL; }
	//<<<+++OPENSOURCE_END
#endif
	/** Get the loaded data pointer.*/
	FX_LPCBYTE				GetData() const;
	/** Get the loaded data size in bytes. */
	FX_DWORD				GetSize() const;

	/**
	 * Detach the data buffer from this stream accessor.
	 * After this call, the caller is now responsible for releasing the data buffer.
	 */
	FX_LPBYTE				DetachData();

	/** Get the image decoder name. */
	const CFX_ByteString&	GetImageDecoder() { return m_ImageDecoder; }
	/** Get the image parameters dictionary. */
	const CPDF_Dictionary*	GetImageParam() { return m_pImageParam; }

protected:
	/** The loaded data. */
	FX_LPBYTE				m_pData;
	/** The size in bytes of the loaded buffer. */
	FX_DWORD				m_dwSize;
	/** Whether the loaded data pointer is newly allocated or just a reference. */
	FX_BOOL					m_bNewBuf;
	/** The cached image decoder name. */
	CFX_ByteString			m_ImageDecoder;
	/** The cached image decoder parameters dictionary. */
	CPDF_Dictionary*		m_pImageParam;
	/** The stream object attached to. */
	const CPDF_Stream*		m_pStream;
	/** The cached source buffer pointer. */
	FX_LPBYTE				m_pSrcData;
};

/**
 * Create a data filter from filter name and parameters, optionally with width and height for image filter.
 *
 * @param[in] name			The PDF filter name.
 * @param[in] pParam		The parameters dictionary for the filter.
 * @param[in] width			The image width for some filter type.
 * @param[in] height		The image height for some filter type.
 */
CFX_DataFilter* FPDF_CreateFilter(FX_BSTR name, const CPDF_Dictionary* pParam, int width=0, int height=0);

/** @brief Internally estimated cached buffer size for stream filter class. */
#define FPDF_FILTER_BUFFER_SIZE		20480

/** @brief Data filter created for accessing PDF stream data. */
class CPDF_StreamFilter : public CFX_Object
{
public:
	/** The destructor. */
	~CPDF_StreamFilter();

	/**
	 * Read a data block. Return number of bytes actually read.
	 * If read size is less than the asked size, it indicates EOF.
	 *
	 * @param[out] buffer	It receives the read data.
	 * @param[in] size		The size in bytes to read.
	 * @return The number of bytes actually read.
	 */
	FX_DWORD			ReadBlock(FX_LPBYTE buffer, FX_DWORD size);

	/** Get current source position (in the raw data stream). */
	FX_DWORD			GetSrcPos() { return m_SrcOffset; }

	/** Get the stream object. */
	const CPDF_Stream*	GetStream() { return m_pStream; }

protected:
	/** The constructor. The object can't be constructed directly. */
	CPDF_StreamFilter() {}
	/**
	 * Read data left over.
	 *
	 * @param[out] buffer	It receives the read data.
	 * @param[in] buf_size	The size in bytes to read.
	 * @return The number of bytes actually read.
	 */
	FX_DWORD			ReadLeftOver(FX_LPBYTE buffer, FX_DWORD buf_size);

	/** The stream object. */
	const CPDF_Stream*	m_pStream;
	/** The data filter chain. */
	CFX_DataFilter*		m_pFilter;
	/** The cached decoded data. */
	CFX_BinaryBuf*		m_pBuffer;
	/** The offset of the cached decoded data in the whole decoded stream data. */
	FX_DWORD			m_BufOffset;
	/** The offset of the cached source encoded data in the whole source encoded stream data. */
	FX_DWORD			m_SrcOffset;
	/** The cached source encoded data. */
	FX_BYTE				m_SrcBuffer[FPDF_FILTER_BUFFER_SIZE];

	friend class CPDF_Stream;
};

/** @brief PDF Null object class. */
class CPDF_Null : public CPDF_Object
{
public:
	/** Create a null object. */
	static CPDF_Null*		Create() { return FX_NEW CPDF_Null(); }

	/** The constructor. */
	CPDF_Null()  { m_Type = PDFOBJ_NULL; }
};

/** @brief PDF Reference object class. */
class CPDF_Reference : public CPDF_Object
{
public:
	/**
	 * Create a reference object with indirect object collection and referred object number.
	 *
	 * @param[in] pDoc		The indirect object collection.
	 * @param[in] objnum	The referred object number.
	 * @return A reference object.
	 */
	static CPDF_Reference*	Create(CPDF_IndirectObjects* pDoc, int objnum)
	{ return FX_NEW CPDF_Reference(pDoc, objnum); }

	/**
	 * Construct a reference object with indirect object collection and referred object number.
	 *
	 * @param[in] pDoc		The indirect object collection.
	 * @param[in] objnum	The referred indirect object number.
	 */
	CPDF_Reference(CPDF_IndirectObjects* pDoc, int objnum)
	{ m_Type = PDFOBJ_REFERENCE; m_pObjList = pDoc; m_RefObjNum = objnum; }

	/** Get the indirect object collection that the referred indirect object belongs to. */
	CPDF_IndirectObjects*	GetObjList() const { return m_pObjList; }
	/** Get the referred object number. */
	FX_DWORD				GetRefObjNum() const { return m_RefObjNum; }
	/**
	 * Change the reference.
	 *
	 * @param[in] pDoc		The new indirect object collection.
	 * @param[in] objnum	The new referred indirect object number.
	 */
	void					SetRef(CPDF_IndirectObjects* pDoc, FX_DWORD objnum);
	/**
	 * Compare with another object.
	 *
	 * @param[in] pOther	The another reference object.
	 * @return Non-zero means identical, otherwise not identical.
	 */
	FX_BOOL					Identical(CPDF_Reference* pOther) const { return m_RefObjNum == pOther->m_RefObjNum; }

protected:
	/** The indirect object collection. */
	CPDF_IndirectObjects*	m_pObjList;
	/** The referred indirect object number. */
	FX_DWORD				m_RefObjNum;

	friend class			CPDF_Object;
};

/** @brief Class for a PDF indirect object collection. This is a base class for both CPDF_Document and CFDF_Document. */
class CPDF_IndirectObjects : public CFX_Object
{
public:
	/**
	 * Construct a indirect object with a document parser.
	 *
	 * @param[in] pParser	The input document parser.
	 */
	CPDF_IndirectObjects(IPDF_DocParser* pParser);
	/** The destructor. */
	~CPDF_IndirectObjects();

	/**
	 * Load an indirect object by an object number.
	 *
	 * @param[in] objnum	The input object number.
	 * @param[in] pContext	Parsing context (see fpdf_parser.h). NULL for no context.
	 * @return An indirect object.
	*/
	CPDF_Object*			GetIndirectObject(FX_DWORD objnum, struct PARSE_CONTEXT* pContext = NULL);

	/**
	 * Get type of an indirect object, without loading the object content.
	 *
	 * @param[in] objnum	The input object number.
	 * @return The type of the indirect object.
	 */
	int						GetIndirectType(FX_DWORD objnum);

	/**
	 * Add an object to indirect object list. The new object number is returned.
	 *
	 * @param[in] pObj		The input object.
	 * @return The new object number.
	 */
	FX_DWORD				AddIndirectObject(CPDF_Object* pObj);
    
	/**
	 * Sometimes, for saving memory space, we can release a loaded indirect object.
	 * However, use this with caution because the object pointer will become invalid.
	 *
	 * @param[in] objnum	The object number to release.
	 */
	void					ReleaseIndirectObject(FX_DWORD objnum);

    //<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
	 * Delete an indirect object. Use this function with caution!
	 *
	 * @param[in] objnum	The object number to delete.
	 */
	void					DeleteIndirectObject(FX_DWORD objnum);
    
	/**
	 * Import an object from its binary format.
	 * This is used when the PDF is fetched in "Progressive Downloading" fashion.
	 * After this function call, the data buffer can be destroyed.
	 * This object must not be encrypted.
	 *
	 * @param[in] pBuffer	The binary data for the indirect object. It must be not encrypted.
	 * @param[in] size		The size in bytes of the binary data.
	 * @return An object.
	 */
	CPDF_Object*			ImportIndirectObject(FX_LPCBYTE pBuffer, FX_DWORD size);

	/**
	 * Import an object from external object collection as a new indirect object.
	 * If the external object refers to other external indirect objects, those indirect objects
	 * are also imported.
	 *
	 * The mapping from old object number to new object number is updated during the import process.
	 *
	 * @param[in] pObj			The object in external object collection.
	 * @param[out] pMapping		It updates the mapping from old object number to new object number.	
	 * @return A new indirect object.
	 */
	CPDF_Object*			ImportExternalObject(CPDF_Object* pObj, CFX_MapPtrToPtr* pMapping);
    //<<<+++OPENSOURCE_END
    
	/**
	 * Insert an indirect object with specified object number.
	 * This is used when the PDF is fetched in "Progressive Downloading" fashion, or parsing FDF.
	 * If an indirect object with the same object number exists, the previous one will be destroyed.
	 *
	 * @param[in] objnum		The new object number of the indirect object to insert.
	 * @param[in] pObj			The indirect object to insert.
	 */
	void					InsertIndirectObject(FX_DWORD objnum, CPDF_Object* pObj);

	/** Get last assigned indirect object number. */
	FX_DWORD				GetLastObjNum() const;

    //<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/** Reload all file based stream when we do reparsing. */
	void					ReloadFileStreams();
    //<<<+++OPENSOURCE_END

	/** Get the start position of the indirect objects. */
	FX_POSITION				GetStartPosition() const { return m_IndirectObjs.GetStartPosition(); }
	/**
	 * Access the indirect object of current position, and move the position to next.
	 *
	 * @param[in,out] rPos	Input current position and receive the next position.
	 * @param[out] objnum	It receives the current object number.
	 * @param[out] pObject	It receives the current indirect object pointer.
	 */
	void					GetNextAssoc(FX_POSITION& rPos, FX_DWORD& objnum, CPDF_Object*& pObject) const
	{ m_IndirectObjs.GetNextAssoc(rPos, (void*&)objnum, (void*&)pObject); }
    
#ifdef _FPDF_OBJ_MODIFIED_
    //<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/** Check if any of the indirect objects are modified, since loading from parser, or last ClearModified. */
	FX_BOOL					IsModified() const;
	/**  Clear the modified flag. */
	void					ClearModified();
    //<<<+++OPENSOURCE_END
#endif

protected:
	/** The indirect object container. From object num to CPDF_Object*. */
	CFX_MapPtrToPtr			m_IndirectObjs;

	/** A parser served as a source of indirect objects. NULL for FDF document. */
	IPDF_DocParser*			m_pParser;
  
	/** The last assigned indirect object number. */
	FX_DWORD				m_LastObjNum;
#ifdef _FPDFAPI_RWLOCK_
	FXMT_RWLOCKOBJECT_DEFINE(m_lockObjIndirect);
#else
	FXMT_LOCKOBJECT_DEFINE(m_lockObjIndirect);
#endif
};

//<<<+++OPENSOURCE_MUST_BEGIN
#endif		// _FPDF_OBJECTS_
//<<<+++OPENSOURCE_MUST_END

/** @} */



